package com.alibaba.cirtus.ots.application.adapter.ability.facade.service.sap;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import com.alibaba.cirtus.ots.application.adapter.ability.model.enums.MnSAPStatus;
import com.alibaba.cirtus.ots.application.adapter.ability.model.enums.PriceEnum;
import com.alibaba.cirtus.ots.application.adapter.ability.model.request.PriceTableDataSapRequest;
import com.alibaba.cirtus.ots.application.adapter.ability.model.request.PriceTableKonpDataSapRequest;
import com.alibaba.cirtus.ots.application.adapter.ability.model.response.CallApiRecordResponse;
import com.alibaba.cirtus.ots.application.adapter.ability.model.response.PriceDimensionResponse;
import com.alibaba.citrus.ots.common.annotation.ProcessInvoker;
import com.alibaba.citrus.ots.common.util.IntegrateUtils;
import com.alibaba.citrus.ots.common.util.SapAndCrmFieldDealUtils;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.sdk.model.Result;

import com.epoch.app.otsapplicationadaptersdk.sap.MnSapCommResponse;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapCommSDO;
import com.epoch.app.otsapplicationadaptersdk.sap.mnsapif001.dto.ExternalSyncPriceRequest;
import com.epoch.app.otsapplicationadaptersdk.sap.mnsapif001.service.MnSapIf001Service;
import com.epoch.app.otspricecenter.dto.request.DimensionProperty;
import com.epoch.app.otspricecenter.dto.request.SyncPriceDimensionConfigDataRequest;
import com.epoch.app.otspricecenter.model.dto.PriceDimensionRequest;
import com.epoch.app.otspricecenter.model.dto.SyncPricePropertyConfigDataResponse;
import com.epoch.app.otspricecenter.model.dto.SyncPriceRecordDataRequest;
import com.epoch.app.otspricecenter.model.dto.SyncPriceRecordDataResponse;
import com.epoch.app.otspricecenter.sdo.PriceDimensionSDO;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;

/**
 * @author hanguo
 * @date 2021/9/25
 * @Description 被动接口，同步价格数据
 */
@Component
public class MnSapIf001ServiceImpl implements MnSapIf001Service {

    private static Log log = Log.getLogger(MnSapIf001ServiceImpl.class);

    private static final String MESSAGE_ID = "messageId";

    private static final String DATA_SOURCE = "sender";

    //这里改成ProcessInvoker拦截  需要重试
    @ProcessInvoker(remark = "MnSapIf001Service")
//    @EpochTransactional(appCode="ots_forecast_sales", dataSourceCode = "ots_forecast_sales", dataSourceType = "app")
    @Override
    public MnSapCommResponse externalSyncPrice(ExternalSyncPriceRequest externalSyncPriceRequest) {

        Map<String, Object> data = Maps.newHashMap();
        if (Objects.nonNull(externalSyncPriceRequest.getData())
                && MapUtils.isNotEmpty((Map<String, Object>)externalSyncPriceRequest.getData())){
            data = (Map<String, Object>) externalSyncPriceRequest.getData();
        }else {
            Object orginalData = IntegrateUtils.safeGetDataObject();
            if (Objects.nonNull(orginalData)){
                data = (Map<String, Object>) orginalData;
            }
        }

        Map<String, Object> messageHeader = Maps.newHashMap();
        if (Objects.nonNull(externalSyncPriceRequest.getMessageHeader())
                && MapUtils.isNotEmpty((Map<String, Object>)externalSyncPriceRequest.getMessageHeader())){
            messageHeader = (Map<String, Object>) externalSyncPriceRequest.getMessageHeader();
        }else {
            Map<String,Object> orginalMessageHeader = IntegrateUtils.safeGetHeaderMap();
            if (MapUtils.isNotEmpty(orginalMessageHeader)){
                messageHeader =  orginalMessageHeader;
            }
        }

        MnSapCommResponse mnSapCommResponse = new MnSapCommResponse();
        mnSapCommResponse.setInterfacePath((String) messageHeader.get("interface"));
        mnSapCommResponse.setMessageId((String) messageHeader.get("messageId"));

        List<MnSapCommSDO> mnSapCommSDOS = Lists.newArrayList();
        MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();

        //不接收超过2M的数据
//        int length = JSONObject.toJSONString(externalSyncPriceRequest).getBytes().length;
//        if(length > PriceEnum.REQUEST_MESSAGE_BYTE_SIZE.getValue()){
//                mnSapCommSDO.setStatus(MnSAPStatus.ERROR.getCode());
//                mnSapCommSDO.setMessage("数据量过大,不能超过"+PriceEnum.REQUEST_MESSAGE_BYTE_SIZE.getValue()+"字节，当前数据大小为"+length+"字节");
//                mnSapCommSDOS.add(mnSapCommSDO);
//                mnSapCommResponse.setData(mnSapCommSDOS);
//                return mnSapCommResponse;
//        }


        //操作过的表结果记录
        List<CallApiRecordResponse> callApiRecordResponses = Lists.newArrayList();

        if (Objects.isNull(data)) {
            return mnSapCommResponse;
        }

        long konpCount = extractedPriceRecord(data, mnSapCommSDO, callApiRecordResponses,messageHeader);

        Map<String, PriceDimensionResponse> dimensionMap = queryPriceDimensionResponseMap(data);

        long tableCount = savePricePropertyConfig(data, mnSapCommSDO, callApiRecordResponses, dimensionMap,messageHeader);

        //记录收到的数据条数
        mnSapCommSDO.setDref1(konpCount + tableCount);
        //没有失败记录时表示同步数据成功
        if (StringUtils.isBlank(mnSapCommSDO.getStatus()) && StringUtils.isBlank(mnSapCommSDO.getMessage())) {
            mnSapCommSDO.setStatus(MnSAPStatus.SUCCESS.getCode());
            mnSapCommSDO.setMessage("同步成功");
        }

        log.info("sapIf001Service价格数据同步结果 result = {}", JSONObject.toJSONString(callApiRecordResponses));

        mnSapCommSDOS.add(mnSapCommSDO);

        mnSapCommResponse.setData(mnSapCommSDOS);
        return mnSapCommResponse;

    }

    /**
     * 保存价格属性配置
     *
     * @param data
     * @param mnSapCommSDO
     * @param callApiRecordResponses
     * @param dimensionMap
     */
    private long savePricePropertyConfig(Map<String, Object> data, MnSapCommSDO mnSapCommSDO,
                                         List<CallApiRecordResponse> callApiRecordResponses,
                                         Map<String, PriceDimensionResponse> dimensionMap,
                                         Map<String,Object> messageHeader) {

        long count = 0;
        //同步价格维度数据，读完一张表的数据后写入,逐行写数据
        List<String> tableDataList = data.keySet().stream().filter(key -> !StringUtils.equals(key, "KONP")).collect(Collectors.toList());
        for (String tableName : tableDataList) {
            //获取维度id和租户id
            String dimensionId = dimensionMap.get(tableName).getDimensionId();
            String tenantId = dimensionMap.get(tableName).getTenantId();

            List<Object> table = (List<Object>) data.get(tableName);
            if (CollectionUtils.isEmpty(table)) {
                continue;
            }
            count += table.size();
            List<PriceTableDataSapRequest> priceTableDataSapRequests = JSONObject.parseArray(JSONObject.toJSONString(table), PriceTableDataSapRequest.class);
            if (CollectionUtils.isEmpty(priceTableDataSapRequests)) {
                continue;
            }


                priceTableDataSapRequests.forEach(tableValue -> {
                    SyncPricePropertyConfigDataResponse syncPricePropertyConfigDataResponse = new SyncPricePropertyConfigDataResponse();
                    SyncPriceDimensionConfigDataRequest syncPriceDimensionConfigDataRequest = new SyncPriceDimensionConfigDataRequest();

                    CallApiRecordResponse callAPISyncPricePropertyConfigDataResponse = new CallApiRecordResponse();
                    try {
                        syncPriceDimensionConfigDataRequest.setTableName(tableName);

                        syncPriceDimensionConfigDataRequest.setDimensionId(dimensionId);

                        List<DimensionProperty> dimensionPropertyList = Lists.newArrayList();
                        {
                            //填入维度组属性数据
                            DimensionProperty orgSalesOrganizationCodeSDO = new DimensionProperty();
                            orgSalesOrganizationCodeSDO.setDimensionName("org_sales_organization_code");
                            orgSalesOrganizationCodeSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getOrgSalesOrganizationCode()));
                            dimensionPropertyList.add(orgSalesOrganizationCodeSDO);

                            DimensionProperty channelCodeSDO = new DimensionProperty();
                            channelCodeSDO.setDimensionName("channel_code");
                            channelCodeSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getChannelCode()));
                            dimensionPropertyList.add(channelCodeSDO);

                            DimensionProperty scItemGroupCodeSDO = new DimensionProperty();
                            scItemGroupCodeSDO.setDimensionName("sc_item_group_code");
                            scItemGroupCodeSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getScItemGroupCode()));
                            dimensionPropertyList.add(scItemGroupCodeSDO);

                            DimensionProperty customerAddressCodeSDO = new DimensionProperty();
                            customerAddressCodeSDO.setDimensionName("customer_send_address_code");
                            customerAddressCodeSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getCustomerAddressCode()));
                            dimensionPropertyList.add(customerAddressCodeSDO);

                            DimensionProperty salesUnitCodeSDO = new DimensionProperty();
                            salesUnitCodeSDO.setDimensionName("sales_unit_code");
                            salesUnitCodeSDO.setDimensionValue(tableValue.getSalesUnitCode());
                            dimensionPropertyList.add(salesUnitCodeSDO);

                            DimensionProperty scItemCodeSDO = new DimensionProperty();
                            scItemCodeSDO.setDimensionName("material_code");
                            scItemCodeSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getMaterialCode()));
                            dimensionPropertyList.add(scItemCodeSDO);

                            DimensionProperty customerSaleAddressCodeSDO = new DimensionProperty();
                            customerSaleAddressCodeSDO.setDimensionName("customer_sale_address_code");
                            customerSaleAddressCodeSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getCustomerCode()));
                            dimensionPropertyList.add(customerSaleAddressCodeSDO);

                            DimensionProperty salesAreaSDO = new DimensionProperty();
                            salesAreaSDO.setDimensionName("sales_area");
                            salesAreaSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getSalesArea()));
                            dimensionPropertyList.add(salesAreaSDO);

                            DimensionProperty customerGroupSDO = new DimensionProperty();
                            customerGroupSDO.setDimensionName("customer_group");
                            customerGroupSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getCustomerGroup()));
                            dimensionPropertyList.add(customerGroupSDO);

                            DimensionProperty factoryCode = new DimensionProperty();
                            factoryCode.setDimensionName("factory_code");
                            factoryCode.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getFactoryCode()));
                            dimensionPropertyList.add(factoryCode);

                            DimensionProperty priceListCodeSDO = new DimensionProperty();
                            priceListCodeSDO.setDimensionName("price_list_code");
                            priceListCodeSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getPriceListCode()));
                            dimensionPropertyList.add(priceListCodeSDO);

                            DimensionProperty storePlaceSDO = new DimensionProperty();
                            storePlaceSDO.setDimensionName("store_place");
                            storePlaceSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getInventoryCode()));
                            dimensionPropertyList.add(storePlaceSDO);

                            DimensionProperty salesDepartmentCodeSDO = new DimensionProperty();
                            salesDepartmentCodeSDO.setDimensionName("sales_department_code");
                            salesDepartmentCodeSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getSaleDepartmentCode()));
                            dimensionPropertyList.add(salesDepartmentCodeSDO);

                            DimensionProperty salesGroupCodeSDO = new DimensionProperty();
                            salesGroupCodeSDO.setDimensionName("sales_group_code");
                            salesGroupCodeSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getSaleDepartmentCode()));
                            dimensionPropertyList.add(salesGroupCodeSDO);

                            DimensionProperty customerCodeSDO = new DimensionProperty();
                            customerCodeSDO.setDimensionName("customer_code");
                            customerCodeSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getCustomerCode()));
                            dimensionPropertyList.add(customerCodeSDO);


                            DimensionProperty departmentCodeSDO = new DimensionProperty();
                            departmentCodeSDO.setDimensionName("department_code");
                            departmentCodeSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getScItemGroupCode()));
                            dimensionPropertyList.add(departmentCodeSDO);

                            DimensionProperty priceAreaSDO = new DimensionProperty();
                            priceAreaSDO.setDimensionName("price_area");
                            priceAreaSDO.setDimensionValue(SapAndCrmFieldDealUtils.generateIdField(tableValue.getSalesArea()));
                            dimensionPropertyList.add(priceAreaSDO);

                        }
                        syncPriceDimensionConfigDataRequest.setDimensionPropertyList(dimensionPropertyList);

                        syncPriceDimensionConfigDataRequest.setPriceTypeId(tableValue.getPriceTypeId());
                        syncPriceDimensionConfigDataRequest.setPriceStartDate(SapAndCrmFieldDealUtils.forPriceStartDate(tableValue.getPriceStartDate()));
                        syncPriceDimensionConfigDataRequest.setPriceEndDate(SapAndCrmFieldDealUtils.forPriceEndDate(tableValue.getPriceEndDate()));
                        syncPriceDimensionConfigDataRequest.setPriceRecordId(tableValue.getPriceRecordId());
                        syncPriceDimensionConfigDataRequest.setTenantId(tenantId);
                        syncPriceDimensionConfigDataRequest.setMessageId((String) messageHeader.get(MESSAGE_ID));
                        syncPriceDimensionConfigDataRequest.setDataSource((String) messageHeader.get(DATA_SOURCE));

                        //调用api写入数据
                        syncPricePropertyConfigDataResponse = externalSyncPrice$CallAPISyncPricePropertyConfigData(syncPriceDimensionConfigDataRequest);

                        callAPISyncPricePropertyConfigDataResponse.setOperateResult(syncPricePropertyConfigDataResponse.getSuccess());
                        callAPISyncPricePropertyConfigDataResponse.setRequestBody(JSONObject.toJSONString(syncPriceDimensionConfigDataRequest));
                        callAPISyncPricePropertyConfigDataResponse.setTableName("ofs_price_property_config");
                        callAPISyncPricePropertyConfigDataResponse.setMessage(syncPricePropertyConfigDataResponse.getMessage());
                        callApiRecordResponses.add(callAPISyncPricePropertyConfigDataResponse);
                    } catch (Exception e) {
                        mnSapCommSDO.setStatus(MnSAPStatus.ERROR.getCode());
                        mnSapCommSDO.setMessage(e.getMessage());

                        //写入结果数据
                        callAPISyncPricePropertyConfigDataResponse.setOperateResult(false);
                        callAPISyncPricePropertyConfigDataResponse.setRequestBody(JSONObject.toJSONString(syncPriceDimensionConfigDataRequest));
                        callAPISyncPricePropertyConfigDataResponse.setTableName("ofs_price_property_config");
                        callAPISyncPricePropertyConfigDataResponse.setMessage(e.getMessage());
                        callApiRecordResponses.add(callAPISyncPricePropertyConfigDataResponse);

                        log.error("同步价格维度数据异常", e);
                    }
                    log.info("同步价格维度数据 result {}", JSONObject.toJSONString(syncPricePropertyConfigDataResponse));

                    //返回结果封装


                });

        }

        return count;
    }

    @NotNull
    private Map<String, PriceDimensionResponse> queryPriceDimensionResponseMap(Map<String, Object> data) {
        List<String> tableNames = data.keySet().stream().filter(key -> !StringUtils.equals(key, "KONP")).collect(Collectors.toList());
        //获取表名称和维度的对应关系
        PriceDimensionRequest batchPriceDimensionRequest = new PriceDimensionRequest();
        batchPriceDimensionRequest.setTableNames(tableNames);
        Result<List<PriceDimensionSDO>> batchPriceDimensionResponse = externalSyncPrice$callBatchPriceDimension(batchPriceDimensionRequest);
        log.info("获取表名称和维度的对应关系 result = {}", JSONObject.toJSONString(batchPriceDimensionResponse));
        Map<String, PriceDimensionResponse> dimensionMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(batchPriceDimensionResponse.getResult())) {
            dimensionMap = JSONObject.parseArray(JSONObject.toJSONString(batchPriceDimensionResponse.getResult()), PriceDimensionResponse.class).stream().collect(Collectors.toMap(PriceDimensionResponse::getDimensionTableName, item -> item));
        }
        return dimensionMap;
    }

    private long extractedPriceRecord(Map<String, Object> data, MnSapCommSDO mnSapCommSDO,
                                      List<CallApiRecordResponse> callApiRecordResponses,
                                      Map<String,Object> messageHeader) {

        long count = 0;

        //同步价格记录数据
        Object konp = data.get("KONP");
        if (Objects.isNull(konp)) {
            return count;
        }

        List<PriceTableKonpDataSapRequest> priceTableKonpDataSapRequests = JSONObject.parseArray(JSONObject.toJSONString(konp), PriceTableKonpDataSapRequest.class);
        if (CollectionUtils.isEmpty(priceTableKonpDataSapRequests)) {
            return count;
        }
        count += priceTableKonpDataSapRequests.size();


        priceTableKonpDataSapRequests.forEach(item -> {
            SyncPriceRecordDataRequest syncPriceRecordDataRequest = new SyncPriceRecordDataRequest();
            syncPriceRecordDataRequest.setPriceRecordId(item.getPriceRecordId());
            String sAmount = item.getAmount();
            if (StringUtils.isNotBlank(sAmount)) {

                BigDecimal amount = new BigDecimal(sAmount);
                BigDecimal multiply = new BigDecimal(PriceEnum.AMOUNT.getValue());
                syncPriceRecordDataRequest.setMoneyAmount(amount.multiply(multiply).longValue());
            }

            if (StringUtils.isNotBlank(item.getDeleteSignal()) && StringUtils.equals(PriceEnum.DELETE.getCode(), item.getDeleteSignal())) {
                    syncPriceRecordDataRequest.setStatus(PriceEnum.DELETE.getValue());
            }
            //分子
            String numerator = item.getNumerator();
            //分母
            String denominator = item.getDenominator();
            Long invalidData = -000000000L;
            //先写死
            syncPriceRecordDataRequest.setMoneyPercentage(invalidData.toString());
            syncPriceRecordDataRequest.setCurrency(item.getCurrency());
            syncPriceRecordDataRequest.setItemCount(SapAndCrmFieldDealUtils.toLong(item.getPriceUint()));
            syncPriceRecordDataRequest.setPriceUnite(item.getMeterUnit());
            syncPriceRecordDataRequest.setTenantId(item.getCustomerCode());
            syncPriceRecordDataRequest.setMessageId((String) messageHeader.get(MESSAGE_ID));
            syncPriceRecordDataRequest.setDataSource((String) messageHeader.get(DATA_SOURCE));

            //TODO need fix 这里的价格更新策略存在老数据覆盖旧数据问题，但是因为1. 价格变更频率不高，2. 页面有手工更新价格入口补偿； 可上线后修复

            //调用api写入数据, 同步价格技术数据
            SyncPriceRecordDataResponse syncPriceRecordDataResponse = externalSyncPrice$CallAPISyncPriceRecordData(syncPriceRecordDataRequest);

            log.info("同步价格记录数据 result = {}", JSONObject.toJSONString(syncPriceRecordDataResponse));

            if (Objects.isNull(syncPriceRecordDataResponse) || !syncPriceRecordDataResponse.getSuccess()) {
                mnSapCommSDO.setStatus(MnSAPStatus.ERROR.getCode());
                mnSapCommSDO.setMessage("同步失败");
            }
            //同步后的结果封装
            CallApiRecordResponse callAPISyncPriceRecordDataResponse = new CallApiRecordResponse();
            callAPISyncPriceRecordDataResponse.setOperateResult(syncPriceRecordDataResponse.getSuccess());
            callAPISyncPriceRecordDataResponse.setRequestBody(JSONObject.toJSONString(syncPriceRecordDataRequest));
            callAPISyncPriceRecordDataResponse.setTableName("ofs_price_record");
            callAPISyncPriceRecordDataResponse.setMessage(syncPriceRecordDataResponse.getMessage());
            callApiRecordResponses.add(callAPISyncPriceRecordDataResponse);

        });



        return count;
    }


}
